package Server;


import java.io.*;
import java.util.*;


/**
 * <p>Title: HttpdConf.java</p>
 *
 * <p>Description: This class will configure your server to the specifications
 * found within the httpd.conf file. </p>
 *
 * @Author: YingLuan Tan, Yves Galang
 * @Course: CSC667
 * @Date: 2012 Spring
 * 
 */

public class HttpdConf {

    /**
     * creates all hashmap objects
     */
    public HttpdConf() 
    {
        _scriptAlias = new HashMap<String, String>();
        _alias = new HashMap<String, String>();
        _mimeType = new HashMap<String, String>();
        _authentication = new Authentication();
        _settings = new HashMap<String, String>();
    }

    
    /**
     * Reads in a httpd.conf file, parses it and saves the data stored within that
     * file. 
     * 
     * @param path 		path to httpd.conf file
     */
    public void readHttpd(String path) throws FileNotFoundException, IOException 
    {
        FileReader fr = new FileReader(new File(path));
        BufferedReader source = new BufferedReader(fr);
        String tmp = source.readLine();
        String[] strArray;
        
        while (tmp != null) 
        { 	
        	tmp = tmp.trim();
            if (tmp.length() > 1 && !tmp.startsWith("#")) 
            {
                tmp = tmp.replaceAll("\"", "");
                strArray = tmp.split(" ");

                if(tmp.startsWith("ScriptAlias"))
                	_scriptAlias.put(strArray[1], strArray[2]);
                else if(tmp.startsWith("Alias"))
                	_alias.put(strArray[1], strArray[2]);
                else if (tmp.startsWith("DirectoryIndex"))
                	_settings.put("DirectoryIndex", tmp.substring(tmp.indexOf(" ") + 1).trim());
                else if (tmp.startsWith("<Directory")) 
                	addAuthen(source , strArray[1]);
                else
                	_settings.put(strArray[0].trim(), strArray[1].trim());
            }
            tmp = source.readLine();
        }
        source.close();
    }
    
    
    /**
     * Adds authentication settings from httpd.conf
     * 
     * @param source	file's input stream
     * @param str		current line to process
     * @throws IOException
     */
    private void addAuthen(BufferedReader source, String str) throws IOException
    {
    	String tmp;
    	String dir;
    	String _name = null, _type = null, _file = null, _user = null;
    	String[] strArray;
    	
    	dir = str.replaceAll(">", "");
    	tmp = source.readLine();
    	
    	while (!tmp.startsWith("</Directory>")) 
    	{
    		tmp = tmp.replaceAll("\"", "");
    		tmp = tmp.trim();
    		strArray = tmp.split(" ");
    		if (tmp.startsWith("AuthName")) 
    			_name = strArray[1];
    		else if (tmp.startsWith("AuthType"))
    			_type = strArray[1];
    		else if (tmp.startsWith("AuthUserFile"))
    			_file = strArray[1];
    		else if (tmp.startsWith("require"))
    			_user = strArray[1].equals("valid-user") ? strArray[1] : strArray[2];
    		
    		tmp = source.readLine();
    	}
    	_authentication.addAuth(dir, _name, _type, _file, _user);
    		
    }
    
    

    /**
     * Function to convert aliases set in httpd.conf file to absolute path. 
     *
     * @param fakeName String which contains the alias of the file or directory
     * @return String value which contains the absolute path to the file or
     *   				directory as determined within the httpd.conf file
     */
    public String solveAlias(String fakeName) 
    {
        String tmp = "/";
        String buf[] = fakeName.split("/");
        if (buf.length > 1) 
            tmp += buf[1];
        else 
        {
            File defPage;
            buf = getSettings("DirectoryIndex").split(" ");
            for (int i = 0; i < buf.length; i++) 
            {
                defPage = new File(getSettings("DocumentRoot") + "/" + buf[i]);
                if (defPage.exists()) 
                    return defPage.getPath();  
            }
        }
        
        if (_alias.get(tmp) == null && _scriptAlias.get(tmp) == null)
        	if(_deniedPage.contains(buf[1]))  
        		return null;
        	else
        		return getSettings("DocumentRoot") + fakeName;
        
        tmp = _alias.containsKey(tmp) ? ((String) _alias.get(tmp)) : ((String) _scriptAlias.get(tmp));
        for (int i = 2; i < buf.length; i++) 
            tmp += "/" + buf[i];
        
        return tmp;
    }

    
    /**
     * Used to read the mime.types file and save all the information from that file
     * into a data structure that can be used to validate file types when
     * generating response messages.
     *
     * @param path String value of path to mime.types file
     */
    public void readMIME(String path) throws FileNotFoundException, IOException 
    {
        BufferedReader source = new BufferedReader(new FileReader(path));
        String buf[];
        String tmp = source.readLine();
        int ind;
        while (tmp != null) {
            if (!(tmp.contains("#") || tmp.length() < 1)) 
            {
                buf = tmp.split("\t");
                if (buf.length > 1) 
                {
                    tmp = buf[0];
                    ind = 1;
                    while (buf[ind].length() < 1) 
                        ind++;
                    
                    buf = buf[ind].split(" ");
                    for (int i = 0; i < buf.length; i++) 
                        _mimeType.put(buf[i], tmp);
                    
                }
            }
            tmp = source.readLine();
        }
    }



    /**
     * Helper function to determine whether the name of a file or directory is an
     * alias for another file or directory as noted in the httpd.conf file.
     *
     * @param name String value of the alias we want to check to determine
     *   whether it is or is not an alias for another file or directory
     * @return true if it is an alias, false otherwise
     */
    public boolean isScript(String name) 
    {
        String buf[] = name.split("/");

        String alias = "/";
        if (buf.length > 1) 
            alias += buf[1];
        
        if (_scriptAlias.containsKey(alias)) 
            return true;
        else
            return false;    
    }


    /**
     * Helper function to see if you've parsed your httpd.conf file properly. Used
     * for debugging purposes.
     */
    public void testPrint() 
    {
        System.out.println("ServerRoot: " + getSettings("ServerRoot"));
        System.out.println("DocumentRoot: " + getSettings("DocumentRoot"));
        System.out.println("ListenPort: " + getSettings("Listen"));
        System.out.println("LogFile: " + getSettings("LogFile"));
        System.out.println("Alias: " + _alias);
        //System.out.println("ScriptAlias: "+scriptAlias+" "+solveAlias(scriptAlias));
    }
    
    
    /**
     * get mime table
     * @return		the hashmap that stores all mime info
     */
    public HashMap<String, String> getMIME() {
        return _mimeType;
    }
    
    /**
     * get Authentication object
     */
    public Authentication getAuthentication() {
        return _authentication;
    }

    
	/**
	 * get httpd configuration. Only single line configurations can be
	 * retrived by this. See httpd.conf for all settings that can be retrieve
	 * 
	 * @param key	the setting to retrieve
	 * @return		the setting's value or null if no such setting
	 */
	public String getSettings(String key)
	{
		if(_settings.containsKey(key))
			return _settings.get(key);
		else
			return null;
	}
	
    private HashMap<String, String> _scriptAlias;
    private HashMap<String, String> _alias;
    private HashMap<String, String> _mimeType;
    private Authentication _authentication;
    private HashMap<String, String> _settings;
    private String _deniedPage = "denied.html";
    
    
    /*  
    public static void main(String[] args)
    {
    HttpdConf tester = new HttpdConf();
    try
    {
    tester.readHttpd("server/httpd.conf");
    } catch (FileNotFoundException ex)
    {
    Logger.getLogger(HttpdConf.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex)
    {
    Logger.getLogger(HttpdConf.class.getName()).log(Level.SEVERE, null, ex);
    }
    
    tester.testPrint();
    }
     */

}

